//	--------------------------------------------------------------------
//	Copyright(C) 2006,2007 Zhao Yukun. All rights reserved.
//	This file is a part of the Xeres system.
//	Xeres 2007
//	Contact : xeres.engine@gmail.com
//	$(reservedInfo)
//	$(reservedDeclaration)
//	--------------------------------------------------------------------
///	@file	<sysinfo.cpp>
///	@path	~/src/lib/system/
///	@date	2007/06/24
///	@desc	system info.

#include "config/config.h"
#include "config/os.h"

namespace xeres {

	// get_system_version
	uint32 get_system_version( void )
	{
		OSVERSIONINFO osinfo;
		memset( &osinfo , 0 , sizeof(OSVERSIONINFO) );
		osinfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
		::GetVersionEx( &osinfo );
		return osinfo.dwMajorVersion * 1000 + osinfo.dwMinorVersion;
	}
	// get application directory
	const wchar_t * get_app_dir( void )
	{
		static wchar_t app_path[OS_MAX_PATH];
		static bool got = false;
		if( !got )
		{
			got = true;
			size_t app_path_len , i;
			if( ( app_path_len = ::GetModuleFileName( NULL , app_path , OS_MAX_PATH ) ) == 0 )
			{
				__win32_error( _S("Cannot get module file name.(%s)\n") );
				abort();
			}
			for( i = app_path_len - 1 ; i > 0 ; --i )
				if( app_path[i+1] == '\\' )
					break;
			app_path[++i] = 0;
			app_path_len = i+1;
		}
		return app_path;
	}

	// get current directory
	const wchar_t * get_cur_dir( void )
	{
		static wchar_t cur_path[OS_MAX_PATH];
		static bool got = false;
		if( !got )
		{
			got = true;
			size_t cur_path_len;
			if( ( cur_path_len = ::GetCurrentDirectory( OS_MAX_PATH , cur_path ) ) == 0 )
			{
				__win32_error( _S("Cannot get current directory.(%s)\n") );
				abort();
			}
		}
		return cur_path;
	}

	// get application name
	const wchar_t * get_app_name( void )
	{
		static wchar_t app_path[OS_MAX_PATH];
		static size_t app_path_len;
		static bool got = false;
		if( !got )
		{
			got = true;
			size_t i;
			if( ( app_path_len = ::GetModuleFileName( NULL , app_path , OS_MAX_PATH ) ) == 0 )
			{
				__win32_error( _S("Cannot get module file name.(%s)\n") );
				abort();
			}
			for( i = app_path_len - 1 ; i > 0 ; --i )
				if( app_path[i+1] == '\\' )
					break;
			app_path[++i] = 0;
			app_path_len = i+1;
		}
		return app_path + app_path_len;
	}

	// get physical memory
	uint64 get_total_physical_memory_size( void )
	{
		MEMORYSTATUSEX mem_status;
		::GlobalMemoryStatusEx( &mem_status );
		return mem_status.ullTotalPhys;
	}
	uint64 get_avail_physical_memory_size( void )
	{
		MEMORYSTATUSEX mem_status;
		::GlobalMemoryStatusEx( &mem_status );
		return mem_status.ullAvailPhys;
	}

	// get virtual memory size
	uint64 get_virtual_memory_size( void )
	{
		MEMORYSTATUSEX mem_status;
		::GlobalMemoryStatusEx( &mem_status );
		return mem_status.ullTotalVirtual;
	}

	// get host-name
	const char * get_host_name( void )
	{
		static char host_name[OS_MAX_HOST];
		static bool got = false;
		if( !got )
		{
			got = true;
			DWORD x = OS_MAX_HOST;
			if( ::GetComputerNameA( host_name , &x ) == FALSE )
			{
				__win32_error( _S("Cannot get host name.(%s)\n") );
				abort();
			}
			host_name[x] = 0;
		}
		return host_name;
	}

	// get number of core
	int get_number_of_core( void )
	{
		SYSTEM_INFO sys_info;
		::GetSystemInfo( &sys_info );
		return sys_info.dwNumberOfProcessors;
	}

	// get_available_core
	int get_available_core( std::vector<bool>& tags )
	{
		tags.resize( get_number_of_core() );
		DWORD_PTR system = 0;
		DWORD_PTR process = 0;
		::GetProcessAffinityMask( ::GetCurrentProcess() , &process , &system );
		DWORD_PTR available = system & process;
		int total = get_number_of_core();
		int avail_count = 0;
		for( int i = 0 ; i < total ; ++i )
		{
			bool avail = ( system & ( (DWORD_PTR)1 << i ) ) ? true : false;
			if( avail )
				++avail_count;
			tags[i] = avail;
		}
		return avail_count;
	}

} // namespace xeres
